#!/usr/bin/env bash

SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
BASE_DIR="$(pwd)"

CYAN="\033[96m"
YELLOW="\033[93m"
RESET="\033[0m"
BOLD="\033[1m"
NORMAL="\033[22m"
CHECK="\xE2\x9C\x94"

PUSH=""
REGISTRY=""
REGISTRY_ORG=""
IMAGE_PREFIX="ui-extension-"
FORCE="false"
GITHUB_BUILD="true"
GITHUB_RELEASE_TAG=""
PODMAN_CONTAINER="false"

GITHUB_SOURCE=$(git config --get remote.origin.url | sed -e 's/^git@.*:\([[:graph:]]*\).git/\1/')
GITHUB_BRANCH="main"

usage() {
  echo "Usage: $0 [<options>] [plugins]"
  echo " options:"
  echo "  -s <repo>    Specify destination GitHub repository (org/name) - defaults to the git origin"
  echo "  -b <branch>  Specify destination GitHub branch"
  echo "  -t <tag>     Specify the Github release tag to build when a release has been tagged and published"
  echo "  -f           Force building the chart even if it already exists"
  echo "  -c           Build as a container image rather than publishing to Github"
  echo "  -p           Push container images on build"
  echo "  -r <name>    Specify destination container registry for built images"
  echo "  -o <name>    Specify destination container registry organization for built images"
  echo "  -i <prefix>  Specify prefix for the built container image (default: 'ui-extension-')"
  echo "  -l           Specify Podman container build"
  exit 1
}

while getopts "hvr:o:pi:fcb:t:s:l" opt; do
  case $opt in
    h)
      usage
      ;;
    p)
      PUSH="--push"
      ;;
    r)
      REGISTRY="${OPTARG%/}/"
      ;;
    o)
      REGISTRY_ORG="${OPTARG}"
      ;;
    i)
      IMAGE_PREFIX="${OPTARG}"
      ;;
    f)
      FORCE="true"
      ;;      
    c)
      GITHUB_BUILD="false"
      ;;
    s)
      GITHUB_BUILD="true"
      GITHUB_SOURCE="${OPTARG}"
      ;;
    b)
      GITHUB_BUILD="true"
      GITHUB_BRANCH="${OPTARG}"
      ;;
    t)
      GITHUB_RELEASE_TAG="${OPTARG}"
      ;;
    l)
      PODMAN_CONTAINER="true"
      ;;
    *)
      usage
      ;;
  esac
done

shift $((OPTIND-1))

PLUGINS=( "$@" )
BUILT="false"

echo -e "${CYAN}${BOLD}Publishing UI Plugins${RESET}"

pushd ${BASE_DIR} > /dev/null

if [ "${GITHUB_BUILD}" == "true" ]; then
  # Determine if gh-pages build is possible
  if [[ "${GITHUB_BRANCH}" == "gh-pages" ]] && ! git show-ref -q gh-pages; then
    echo -e "${YELLOW}'gh-pages' branch not found, this branch must exist before running this script${RESET}"
    exit 1
  fi

  echo -e "${CYAN}GitHub Repository: ${GITHUB_SOURCE}${RESET}"
  echo -e "${CYAN}GitHub Branch    : ${GITHUB_BRANCH}${RESET}"

  if [[ -n "${GITHUB_RELEASE_TAG}" ]]; then
    echo -e "${CYAN}GitHub Release   : ${GITHUB_RELEASE_TAG}${RESET}"
  fi
else
  echo -e ${CYAN}"Image prefix: ${IMAGE_PREFIX}${RESET}"
fi

# --------------------------------------------------------------------------------
# Check that we have the required commands avaialble for this script
# --------------------------------------------------------------------------------

if ! [[ -f ${BASE_DIR}/package.json ]]; then
  echo -e "${YELLOW}You must run from the top-level folder${RESET}"
  exit 1
fi

# Check this is a Rancher extension
IS_SHELL=$(grep "\"@rancher/shell" package.json -c)

if [ "${IS_SHELL}" -ne 1 ]; then
  echo -e "${YELLOW}Current folder does not appear to contain Rancher Extensions${RESET}"
  exit 1
fi

if ! [[ -d ${BASE_DIR}/node_modules ]]; then
  echo -e "${YELLOW}You must run ${BOLD}yarn install${NORMAL} before running this script${RESET}"
  exit 1
fi

COMMANDS=("node" "jq" "yq" "git" "helm" "yarn")
if [ "${GITHUB_BUILD}" == "false" ]; then
  if [ "${PODMAN_CONTAINER}" == "true" ]; then
    COMMANDS+=("podman")
  else
    COMMANDS+=("docker")
  fi
fi

HAVE_COMMANDS="true"
for CMD in "${COMMANDS[@]}"
do
  if ! command -v ${CMD} >/dev/null; then
    echo -e "${YELLOW}This script requires ${BOLD}${CMD}${NORMAL} to be installed and on your PATH${RESET}"
    HAVE_COMMANDS="false"
  fi
done

if [ "${HAVE_COMMANDS}" == "false" ]; then
  exit 1
fi

# --------------------------------------------------------------------------------
# Only do conatiner args checks if not GitHub publish
# --------------------------------------------------------------------------------
if [ "${GITHUB_BUILD}" == "false" ]; then
  BASE_EXT=$(jq -r .name ${BASE_DIR}/package.json)
  EXT_VERSION=$(jq -r .version ${BASE_DIR}/package.json)

  if [ -z ${EXT_VERSION} ]; then
    EXT_VERSION="0.0.0"
  fi

  if [[ -z ${REGISTRY_ORG} ]]; then
    # Infer that the user has the same Docker registry org as their GitHub org
    GITHUB_REPO=$(git config --get remote.origin.url | sed -e 's/^git@.*:\([[:graph:]]*\).git/\1/')
    REGISTRY_ORG=$(dirname ${GITHUB_REPO})
    echo -e "Inferring built images will reside in registry organization ${CYAN}${BOLD}${REGISTRY}${REGISTRY_ORG}${RESET} based on configured origin remote pointing to ${CYAN}${BOLD}${GITHUB_REPO}${RESET}"
  fi

  if [[ -z ${REGISTRY_ORG} ]]; then
    # Inferring from the git config still failed
    echo "Cannot build images without valid organization for Docker images. Unable to infer REGISTRY_ORG="
    exit 1
  fi

  if [ -n "${GITHUB_RELEASE_TAG}" ] && [[ ${GITHUB_RELEASE_TAG} != "${BASE_EXT}-${EXT_VERSION}" ]]; then
    echo -e "${YELLOW}Github tagged release name does not match ${RESET}${BOLD}${BASE_EXT}-${EXT_VERSION}${RESET}"
    echo -e "${YELLOW}Stopping build${RESET}"
    exit 1
  fi

  if [ "${PODMAN_CONTAINER}" == "false" ]; then
    docker images > /dev/null
    if [ $? -ne 0 ]; then
      echo "docker is not running - this is required to build container images for the UI Plugins"
      exit 1
    fi
  fi
fi

ASSETS=${BASE_DIR}/assets
CHARTS=${BASE_DIR}/charts
mkdir -p ${ASSETS}
mkdir -p ${CHARTS}

TMP=${BASE_DIR}/tmp
CHART_TMP=${BASE_DIR}/tmp/_charts
rm -rf ${TMP}
mkdir -p ${TMP}

# --------------------------------------------------------------------------------
# Copy the plugin server template into the temporary folder
# --------------------------------------------------------------------------------
pushd ${TMP} > /dev/null
cp -r ${SCRIPT_DIR}/helm .
popd > /dev/null

CHART_TEMPLATE=${BASE_DIR}/tmp/helm
ROOT_INDEX=${BASE_DIR}/index.yaml

# --------------------------------------------------------------------------------
# Iterate through all packages - built them all or build only those specified on the command line
# --------------------------------------------------------------------------------
for d in pkg/*/ ; do
  pkg=$(basename $d)

  if [ -z "$1" ] || [[ " ${PLUGINS[*]} " =~ " ${pkg} " ]]; then
    # Check we don't already have a published version by looking in the assets folder
    PKG_VERSION=$(jq -r .version ./pkg/${pkg}/package.json)
    PKG_NAME="${pkg}-${PKG_VERSION}"
    PKG_ASSET=${ASSETS}/${pkg}/${PKG_NAME}.tgz

    # Skip the build for a package that does not match the tagged release name
    if [[ -n "${GITHUB_RELEASE_TAG}" ]] && [ ${GITHUB_BUILD} == "true" ] && [[ ${GITHUB_RELEASE_TAG} != ${PKG_NAME} ]]; then
      echo -e "${YELLOW}Github release tag ${RESET}${BOLD}${GITHUB_RELEASE_TAG}${RESET}${YELLOW} does not match asset name${RESET}"
      echo -e "${YELLOW}Skipping ${RESET}${BOLD}${PKG_NAME}${RESET}"
      continue
    fi

    echo -e "${CYAN}${BOLD}Building plugin: ${pkg} (${PKG_VERSION}) ${RESET}"

    echo "Package version: ${PKG_VERSION}"
    echo "Package folder:  ${PKG_NAME}"

    # --------------------------------------------------------------------------------
    # Build the plugin from source
    # --------------------------------------------------------------------------------
    echo -e "${CYAN}Building plugin from source code${RESET}"
    FORCE_COLOR=1 yarn build-pkg $pkg | cat

    echo -e "${CYAN}Adding plugin code ...${RESET}"

    EXT_FOLDER=${BASE_DIR}/extensions/${pkg}/${PKG_VERSION}
    PKG_DIST="${BASE_DIR}/dist-pkg/${PKG_NAME}"

    rm -rf ${EXT_FOLDER}

    mkdir -p ${EXT_FOLDER}/plugin

    # Copy the code into the folder
    cp -R ${PKG_DIST}/* ${EXT_FOLDER}/plugin

    pushd ${BASE_DIR}/extensions/${pkg}/${PKG_VERSION} > /dev/null
    rm -f plugin/report.html
    find plugin -type f | sort > files.txt
    popd > /dev/null

    # --------------------------------------------------------------------------------
    # Create the Helm chart
    # --------------------------------------------------------------------------------

    if [ -f ${PKG_ASSET} ] && [ "${FORCE}" == "false" ]; then
      echo -e "${YELLOW}Helm chart has already been created - skipping (run with -f to force build)${RESET}"
      continue;
    fi

    CHART_FOLDER=${CHARTS}/${pkg}/${PKG_VERSION}

    mkdir -p ${ASSETS}/${pkg}
    rm -rf ${CHART_FOLDER}
    mkdir -p ${CHART_FOLDER}

    cp -R ${CHART_TEMPLATE}/charts/ui-plugin-server/* ${CHART_FOLDER}

    # Update Chart.yaml and values.yaml from the package file metadata
    # Use the script from the template repository
    echo -e "${CYAN}Patching Helm chart template${RESET}"

    CHART=${CHART_FOLDER} REGISTRY="${REGISTRY}" ORG="${REGISTRY_ORG}" PACKAGE_JSON=${BASE_DIR}/pkg/${pkg}/package.json ${CHART_TEMPLATE}/scripts/patch

    # Copy README file from the plugin to the Helm chart, if there is one
    if [ -f "./pkg/${pkg}/README.md" ]; then
      cp ./pkg/${pkg}/README.md ${CHART_FOLDER}/README.md
    fi

    pushd ${CHART_FOLDER}/templates > /dev/null
    
    if [ "${GITHUB_BUILD}" == "true" ]; then
      echo "Patching for GitHub build"
      ENDPOINT=https://raw.githubusercontent.com/${GITHUB_SOURCE}/${GITHUB_BRANCH}/extensions/${pkg}/${PKG_VERSION}
    else
      echo "Patching for container build"
      ENDPOINT=http://${IMAGE_PREFIX}${BASE_EXT}-svc.cattle-ui-plugin-system:8080/plugin/${PKG_NAME}
    fi
    sed -i.bak -e 's@endpoint: .*@endpoint: '"${ENDPOINT}"'@g' cr.yaml
    rm *.bak
    popd > /dev/null

    # Additional patches
    ${SCRIPT_DIR}/helmpatch ${CHART_FOLDER} "${BASE_DIR}/pkg/${pkg}/package.json"

    # Package into a .tgz helm chart
    helm package ${CHART_FOLDER} -d ${ASSETS}/${pkg}

    # --------------------------------------------------------------------------------
    # Update the helm index just for this chart 
    # --------------------------------------------------------------------------------
    HELM_INDEX=${BASE_DIR}/index.yaml

    if [ -f "${HELM_INDEX}" ]; then
      UPDATE="--merge ${HELM_INDEX}"
    elif [ "${GITHUB_BUILD}" == "true" ] && [[ -n ${GITHUB_SOURCE} ]]; then
      # Check if git branch contains index.yaml
      GITHUB_SOURCE=$(echo -e "${GITHUB_SOURCE}" | sed 's/https:\/\///g')

      wget -P ${BASE_DIR} https://raw.githubusercontent.com/${GITHUB_SOURCE}/${GITHUB_BRANCH}/index.yaml 2>/dev/null
      HELM_INDEX="${BASE_DIR}/index.yaml"

      if [ -f "${HELM_INDEX}" ]; then
        UPDATE="--merge ${HELM_INDEX}"
      fi
    fi

    # Base URL referencing assets directly from GitHub
    BASE_URL="assets/"

    # Relative URL references assets within the container deployment
    RELATIVE_URL="plugin/"
    
    rm -rf ${CHART_TMP}
    mkdir -p ${CHART_TMP}
    cp ${ASSETS}/${pkg}/*.tgz ${CHART_TMP}

    if [ "${GITHUB_BUILD}" == "true" ]; then
      helm repo index ${ASSETS} --url ${BASE_URL} ${UPDATE}
    elif ! [ -e "${HELM_INDEX}" ]; then
      helm repo index ${ASSETS} --url ${RELATIVE_URL}
    fi

    BUILT="true"
  fi
done

if [ "${GITHUB_BUILD}" == "true" ] && [[ -n "${GITHUB_RELEASE_TAG}" ]] && [ "${BUILT}" == "false" ]; then
  echo -e "${YELLOW}Github release tag ${RESET}${BOLD}${GITHUB_RELEASE_TAG}${RESET}${YELLOW} did not match any package name.${RESET}"
  echo -e "${YELLOW}Stopping build${RESET}"

  rm -rf ${CHART_TMP}
  rm -rf ${TMP} 
  exit 1
fi

if [ -f ${ROOT_INDEX} ] && [ "${GITHUB_BUILD}" == "false" ]; then
  UPDATE="--merge ${ROOT_INDEX}"
  helm repo index ${ASSETS} ${UPDATE}
fi

if [ -f ${ASSETS}/index.yaml ] && ! [ -e "${ROOT_INDEX}" ]; then
  cp ${ASSETS}/index.yaml ${BASE_DIR}
fi

if [ "${GITHUB_BUILD}" == "false" ]; then
  echo -e "${CYAN}Base extension: ${BASE_EXT}${RESET}"
  echo -e "${CYAN}Extension version: ${EXT_VERSION}${RESET}"

  # Build the container image
  ${SCRIPT_DIR}/bundle "${BASE_EXT}" "${EXT_VERSION}" "${REGISTRY}" "${REGISTRY_ORG}" "${IMAGE_PREFIX}" "${PUSH}" "${PODMAN_CONTAINER}"
else
  rm -rf ${CHART_TEMPLATE}
fi

if [ "${GITHUB_BUILD}" == "true" ] && [ -f ${ROOT_INDEX} ]; then
  if [[ -n "${GITHUB_RELEASE_TAG}" ]] && [ -f ${ASSETS}/index.yaml ]; then
    cp ${ASSETS}/index.yaml tmp
  else
    cp ${ROOT_INDEX} tmp
  fi
fi

if [ "${GITHUB_BUILD}" == "true" ] && [ "${BUILT}" == "true" ]; then
  echo -e "${BOLD}${CYAN}Packaging for Github Build${RESET}"
  # Make temp directory for workflow build artifact
  mkdir -p tmp/{assets,charts,extensions}

  cp -r ${ASSETS}/* tmp/assets
  cp -r ${CHARTS}/* tmp/charts
  cp -r ${BASE_DIR}/extensions/* tmp/extensions
fi

if [ "${BUILT}" == "true" ]; then
  echo -e "${CYAN}${BOLD}${CHECK} One or more packages built${RESET}"
fi

# Clean up
rm -rf ${CHART_TMP}

if [ "${GITHUB_BUILD}" == "false" ]; then
  rm -rf ${TMP} ${ASSETS} ${CHARTS} ${BASE_DIR}/extensions ${BASE_DIR}/dist-pkg ${ROOT_INDEX}
fi
